home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / xover.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  15KB  |  737 lines

  1. /* -*- mode: C; mode: fold; -*- */
  2. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  3.  *
  4.  * This file is part of slrn.
  5.  *
  6.  * Slrn is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation; either version 2, or (at your option) any
  9.  * later version.
  10.  * 
  11.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with Slrn; see the file COPYING.  If not, write to the Free
  18.  * Software Foundation, 59 Temple Place - Suite 330, 
  19.  * Boston, MA  02111-1307, USA.
  20.  */
  21.  
  22.  
  23. #include "config.h"
  24.  
  25. #ifndef SLRNPULL_CODE
  26. # include "slrnfeat.h"
  27. #endif
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31.  
  32. #ifdef HAVE_STDLIB_H
  33. # include <stdlib.h>
  34. #endif
  35.  
  36. #include <slang.h>
  37. #include "jdmacros.h"
  38.  
  39. #include "util.h"
  40. #include "ttymsg.h"
  41. #include "hash.h"
  42.  
  43. #ifndef SLRNPULL_CODE
  44. # include "group.h"
  45. # include "art.h"
  46. #endif
  47.  
  48. #include "xover.h"
  49.  
  50. #ifndef SLRNPULL_CODE
  51. static int extract_id_from_xref (char *);
  52. #endif
  53.  
  54. typedef struct /*{{{*/
  55. {
  56.    char *name;
  57.    unsigned int name_len;
  58.    char *value;
  59. }
  60.  
  61. /*}}}*/
  62. Header_Type;
  63.  
  64. #define MAX_PARSED_HEADERS 36
  65. static Header_Type Parsed_Headers [MAX_PARSED_HEADERS] = /*{{{*/
  66. {
  67. #define SUBJECT_OFFSET    0
  68.      {"Subject", 7, NULL},
  69. #define FROM_OFFSET    1
  70.      {"From", 4, NULL},
  71. #define DATE_OFFSET    2
  72.      {"Date", 4, NULL},
  73. #define MSGID_OFFSET    3
  74.      {"Message-ID", 10, NULL},
  75. #define REFS_OFFSET    4
  76.      {"References", 10, NULL},
  77. #define LINES_OFFSET    5
  78.      {"Lines", 5, NULL},
  79. #define XREF_OFFSET    6
  80.      {"Xref", 4, NULL},
  81.    
  82.    /* Technically, bytes is in the overview file.  However, this value
  83.     * is not stored in slrn's article structure.
  84.     */
  85. #define BYTES_OFFSET    7
  86.      {"Bytes", 5, NULL}
  87. #define NON_XOVER_HEADER_START 7
  88. };
  89.  
  90. /*}}}*/
  91.  
  92. /* The pointers in the above structure will point to the following buffer. */
  93. static char *Malloced_Headers;
  94.  
  95. static void parse_headers (void) /*{{{*/
  96. {
  97.    unsigned int i;
  98.    unsigned int next_slot;
  99.    char *h, ch;
  100.    
  101.    for (i = 0; i < NON_XOVER_HEADER_START; i++)
  102.      Parsed_Headers[i].value = NULL;
  103.    
  104.    for (i = NON_XOVER_HEADER_START; i < MAX_PARSED_HEADERS; i++)
  105.      {
  106.     Parsed_Headers[i].name = NULL;
  107.     Parsed_Headers[i].value = NULL;
  108.      }
  109.    
  110.    h = Malloced_Headers;
  111.    next_slot = NON_XOVER_HEADER_START;
  112.    
  113.    while (*h != 0)
  114.      {
  115.     char *colon;
  116.     unsigned int len;
  117.     
  118.     colon = h;
  119.     while (*colon && (*colon != ':')) colon++;
  120.     
  121.     if (*colon != ':')
  122.       break;
  123.     
  124.     *colon = 0;
  125.     len = (unsigned int) (colon - h);
  126.     
  127.     colon++;
  128.     if (*colon == ' ') colon++;   /* space is required to be there */
  129.     
  130.     for (i = 0; i < NON_XOVER_HEADER_START; i++)
  131.       {
  132.          if ((Parsed_Headers[i].value != NULL)
  133.          || (len != Parsed_Headers[i].name_len)
  134.          || (slrn_case_strcmp ((unsigned char *)h, 
  135.                        (unsigned char *) Parsed_Headers[i].name)))
  136.            continue;
  137.          
  138.          Parsed_Headers[i].value = colon;
  139.          break;
  140.       }
  141.     
  142.     if ((i == NON_XOVER_HEADER_START) && (next_slot < MAX_PARSED_HEADERS))
  143.       {
  144.          /* Must not be an XOVER header.  Add it to list. */
  145.          Parsed_Headers[next_slot].name = h;
  146.          Parsed_Headers[next_slot].name_len = len;
  147.          Parsed_Headers[next_slot].value = colon;
  148.          next_slot++;
  149.       }
  150.     
  151.     /* Now skip to next header line and take care of continuation if
  152.      * present.
  153.      */
  154.     
  155.     h = colon;
  156.     while (0 != (ch = *h))
  157.       {
  158.          if (ch == '\n')
  159.            {
  160.           ch = *(h + 1);
  161.           if ((ch == ' ') || (ch == '\t'))
  162.             {
  163.                *h++ = ' ';
  164.             }
  165.           else 
  166.             {
  167.                *h++ = 0;
  168.                break;
  169.             }
  170.            }
  171.          
  172.          if (ch == '\t') *h = ' ';
  173.  
  174.          h++;
  175.       }
  176.      }
  177. }
  178.  
  179. /*}}}*/
  180.  
  181. #if SLRN_HAS_FAKE_REFS
  182. static char *fake_refs_from_inreply_to (char *buf, unsigned int buflen)
  183. {
  184.    char *p, ch;
  185.    Header_Type *h, *hmax;
  186.  
  187.    h = Parsed_Headers + NON_XOVER_HEADER_START;
  188.    hmax = Parsed_Headers + MAX_PARSED_HEADERS;
  189.    
  190.    while (1)
  191.      {
  192.     if ((h == hmax)
  193.         || (NULL == (p = h->name)))
  194.       return NULL;
  195.     
  196.     if ((11 == h->name_len)
  197.         && (0 == slrn_case_strcmp ((unsigned char *)p, (unsigned char *)"In-Reply-To")))
  198.       break;
  199.  
  200.     h++;
  201.      }
  202.    
  203.    p = h->value;
  204.  
  205.    while ((ch = *p) != 0)
  206.      {
  207.     unsigned int len;
  208.     char *pend;
  209.  
  210.     if (ch != '<')
  211.       {
  212.          p++;
  213.          if ((ch == 'f') || (ch == 'F'))
  214.            {
  215.           /* heuristic: stop if we find 'From' or 'from'
  216.            * to avoid interpreting an email address as a
  217.            * message-id in cases like this:
  218.            * "In-Reply-To: A message from <olly@muscat.co.uk>"
  219.            */
  220.           if (0 == strncmp (p, "rom", 3))
  221.             return NULL;
  222.            }
  223.          continue;
  224.       }
  225.  
  226.     /* found a message-id */
  227.     if (NULL == (pend = slrn_strchr (p, '>')))
  228.       return NULL;
  229.           
  230.     len = 1 + (pend - p); /* include the '>' */
  231.          
  232.     if (len >= buflen)
  233.       return NULL;
  234.          
  235.     strncpy (buf, p, len);
  236.     buf [len] = '\0';
  237.     return buf;
  238.      }
  239.     
  240.    return NULL;
  241. }
  242. #endif
  243.    
  244. static int parsed_headers_to_xover (int id, Slrn_XOver_Type *xov) /*{{{*/
  245. {
  246.    unsigned int len;
  247.    char *subj, *from, *date, *msgid, *refs, *bytes, *lines, *xref;
  248.    char *buf;
  249. #if SLRN_HAS_FAKE_REFS
  250.    char fake_ref_buf [512];
  251. #endif
  252.  
  253.    if (NULL == (subj = Parsed_Headers[SUBJECT_OFFSET].value))
  254.      subj = "";
  255.    if (NULL == (from = Parsed_Headers[FROM_OFFSET].value))
  256.      from = "";
  257.    if (NULL == (date = Parsed_Headers[DATE_OFFSET].value))
  258.      date = "";
  259.    if (NULL == (msgid = Parsed_Headers[MSGID_OFFSET].value))
  260.      msgid = "";
  261.  
  262.    if ((NULL == (refs = Parsed_Headers[REFS_OFFSET].value))
  263. #if SLRN_HAS_FAKE_REFS
  264.        && (NULL == (refs = fake_refs_from_inreply_to (fake_ref_buf, sizeof (fake_ref_buf))))
  265. #endif
  266.        )
  267.      refs = "";
  268.  
  269.    if (NULL == (xref = Parsed_Headers[XREF_OFFSET].value))
  270.      xref = "";
  271.    if (NULL == (lines = Parsed_Headers[LINES_OFFSET].value))
  272.      lines = "";
  273.    if (NULL == (bytes = Parsed_Headers[BYTES_OFFSET].value))
  274.      bytes = "";
  275.    
  276.    len = strlen (subj) + strlen (from) + strlen (date) + strlen (msgid)
  277.      + strlen (refs) + strlen (xref) + 6;
  278.  
  279.    buf = slrn_malloc (len, 0, 1);
  280.    if (buf == NULL)
  281.      return -1;
  282.  
  283.    xov->subject_malloced = buf;
  284.    strcpy (buf, subj);
  285.    buf += strlen (subj) + 1;
  286.    
  287.    xov->from = buf;
  288.    strcpy (buf, from);
  289.    buf += strlen (from) + 1;
  290.  
  291.    xov->date = buf;
  292.    strcpy (buf, date);
  293.    buf += strlen (date) + 1;
  294.    
  295.    xov->message_id = buf;
  296.    strcpy (buf, msgid);
  297.    buf += strlen (msgid) + 1;
  298.  
  299.    xov->references = buf;
  300.    strcpy (buf, refs);
  301.    buf += strlen (refs) + 1;
  302.    
  303.    xov->xref = buf;
  304.    strcpy (buf, xref);
  305.    buf += strlen (xref) + 1;
  306.  
  307.    xov->bytes = atoi (bytes);
  308.    xov->lines = atoi (lines);
  309.  
  310. #ifndef SLRNPULL_CODE
  311.    if (id == -1)
  312.      id = extract_id_from_xref (xov->xref);
  313. #endif
  314.  
  315.    xov->id = id;
  316.  
  317.    return 0;
  318. }
  319.  
  320. /*}}}*/
  321.  
  322. char *slrn_get_extra_xover_header (char *hdr) /*{{{*/
  323. {
  324.    Header_Type *h, *hmax;
  325.    unsigned int len;
  326.    
  327.    h = Parsed_Headers + NON_XOVER_HEADER_START;
  328.    hmax = Parsed_Headers + MAX_PARSED_HEADERS;
  329.    len = strlen (hdr);
  330.    
  331.    while ((h < hmax) && (h->value != NULL))
  332.      {
  333.     if ((len == h->name_len)
  334.         && (0 == slrn_case_strcmp ((unsigned char *)h->name,
  335.                        (unsigned char *)hdr)))
  336.       return h->value;
  337.     
  338.     h++;
  339.      }
  340.    return NULL;
  341. }
  342.  
  343. /*}}}*/
  344.  
  345. #ifdef SLRNPULL_CODE
  346. static int xover_parse_head (int id, char *headers, Slrn_XOver_Type *xov) /*{{{*/
  347. {
  348.    slrn_free (Malloced_Headers);
  349.    
  350.    if (NULL == (Malloced_Headers = slrn_strmalloc (headers, 1)))
  351.      return -1;
  352.    
  353.    parse_headers ();
  354.    
  355.    return parsed_headers_to_xover (id, xov);
  356. }
  357. /*}}}*/
  358. #endif
  359.  
  360. void slrn_map_xover_to_header (Slrn_XOver_Type *xov, Slrn_Header_Type *h)
  361. {   
  362.    char *m;
  363.    
  364.    h->subject = xov->subject_malloced;
  365.    h->number = xov->id;
  366.    h->from = xov->from;
  367.    h->date = xov->date;
  368.    h->refs = xov->references;
  369.    h->lines = xov->lines;
  370.    h->xref = xov->xref;
  371.    
  372.    /* Since the subject has been malloced, the message_id pointer can be changed.
  373.     */
  374.    m = xov->message_id;
  375.    while ((*m != '<') && (*m != 0))
  376.      m++;
  377.    
  378.    if (*m != 0)
  379.      {
  380.     h->msgid = m;
  381.     m = slrn_strchr (m, '>');
  382.